6.8 How to push data to client

  1. Motivations
    • Look the above example of server time. The messages keep coming from the server script on cs.tru.ca, without any further requests.
    • In TRUQA, how to notify the users there is now a new question?
    • In TRUQA, how to display server time?
    • How about 'Live/Developing' in CBCnews?
    • The whole current page should NOT be redisplayed.
  2. How to push data to the client?
    • Do you have any ideas?
      • Polling - The client repeatedly requests information from the server.
      • Long Polling - A variation of polling technique. If the server does not have any information available for the client when the poll is received, instead of sending an empty response, the server holds the request open and waits for response information to become available.
      • How can you implement polling for News or notification feeding?
      • Can you use iframe or AJAX for polling?
    • But the above ideas are still not perfect. Why?
      • The server program has to wait till the client program sends a request. There can be some delay.
      • Any other ideas?
        • WebSocket that is a protocol providing stateful full-duplex communications channels over a single TCP connection.
        • However many applications do not need stateful full-duplex communications. Just information from the server is good enough.
        • Another good solution is Server-Sent Event (SSE).
  3. How to use Server-Sent Event(SSE)?
    • What is SSE?
      • Read 'Server-Sent Events - One Way Messaging' and 'Receive Server-Sent Event Notifications' in HTML5 Server-Sent Events.
        • When is SSE used?
        • Give several examples of using SSE.
        • Is SSE AJAX?
        • What object is used to receive SSE notifications?
        • What kind of events are used?
        • How to check if your browser supports SSE?
        • In the example, addEventListener() can be used instead of onmessage?     Yes
        • Advanced questions: SSE objects are not HTML element objects. How is it possible to trigger the 'message' event on the SSE objects? What triggers the 'message' event? Can you write the code that uses custom events?
    • How to use SSE in the client?
      1. Create an EventSource object with the URL of a server program that pushes information.
      2. Wait for the message events that include the messages sent from the server program. The server program can send messages any time, e.g., by echoing string messages that include event names. But the 'content-type' in the HTML packet should be 'text/event-stream'.
    • SSE message format (Line by line ending with an empty line) sent from the server
      "retry: ...\n"          <- Just once. Do not use ' ... ', because ' ... ' does not interpret \n as the real newline.
      "event: ...\n"          <- This is optional. The default event name is 'message'.
      "id: ...\n"             <- This is an user defined id and is optional.
      "data: ...any text based message, including JSON...\n"
      "\n"                    <- End of the message.
      
    • Event types on EventSource:
      • open
      • error
      • message - default event for data; when an event is not defined in the SSE message.
      • user-defined event - when a different event name is defined in the SSE message.
    • Event object on EventSource has ...
      • origin
      • id
      • data
    • EventSource object has ...
      • readyState
      • close()
    • Here is an example to display date/time coming from the server.
      //---- CLIENT:
      
      window.addEventListener('load', function() { ... start_sse(); ... });
      
      function start_sse()
      {
          if ('EventSource' in window)  // Only when this browser supports SSE
          {
              var source = new EventSource("server_time.php?subject=COMP&no=3540");  // Can a URL include query?
              // The browser usually reopens every 3 seconds. 
              // This can be controlled by the server using "retry:".
              source.onopen = function(event) { ... }
              source.onerror = function(event) { ... }
              source.onmessage = function(event) {
                  // if (e.origin != '...') return;  // for security concern
                  if (event.id == 'CLOSE')  // user-defined id
                      source.close();
                  else  // event.data
                      document.getElementById("server_time").innerHTML = 
                              "The server time with 'message': " + event.data;
              };
              source.addEventListener('newevent',  // a new user-defined event
                                                   // Can you use source.onnewevent = ...?
                  function(event) {
                      if (event.id == 'CLOSE')
                          source.close();
                      else  // event.data
                          document.getElementById('server_time').innerHTML = 
                              "The server time with 'newevent': " + event.data;
                  },);
          }
          else {
              document.getElementById('message').innerHTML = 'No EventSource';
          }
      }
      
      //---- SERVER: server_time.php
      
      <?php
          $subject = $_GET['subject'];
          $number = $_GET['no'];
              
          header("Content-Type: text/event-stream");  // This functions sends a raw HTTP header to a client.
          header('Cache-Control: no-cache');          // You may refer to http://www.w3schools.com/php/func_http_header.asp
      
          echo "retry: 3000\n";  // 3 seconds
                                        // Use double quotes. 
                                        // If single quotes are used, \n will not be interpreted as the newline character, and 
                                        // this will make a trouble.
          $count = 0;
          while ($count < 3600) {  // just one hour
              if ($count++ % 2 == 0)
                  echo "event: newevent\n";  // use the new user-defined event 'newevent'
              else
                  ;  // use the default event 'message'
              $time = date('r');
              echo "data: $time\n";
              echo "\n";  // the end of a message
      
              ob_flush();  // flush the output buffer
              flush();  // flush the system buffer
                  
              sleep(1);  // sleep 1 second
          }
      ?>
      
    • Can you see in the above example how to make a PHP program run for a long time? Is it possible to send a form data to a PHP program that is currently running?
    • Here is another good reference - Server-Sent Events (SSE).
  4. Is it possible to make a bidirectional communication channel using SSE for real time applications such as chatting?

  5. Learning outcomes
    • How to use SSE for pushing.